package com.jinyang.jetpackdemo.activity

import android.annotation.SuppressLint
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.lifecycle.lifecycleScope
import coil.load
import com.jinyang.jetpackdemo.R
import com.jinyang.jetpackdemo.util.LjyLogUtil
import com.jinyang.jetpackdemo.util.NetUtil
import kotlinx.android.synthetic.main.activity_ok_http_demo.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import okhttp3.*
import java.io.File
import java.io.IOException
import java.text.SimpleDateFormat
import java.util.*
import java.util.concurrent.TimeUnit
import okhttp3.OkHttpClient
import okhttp3.CacheControl
import java.io.FileOutputStream
import okhttp3.RequestBody

import okhttp3.MultipartBody


class OkHttpDemoActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_ok_http_demo)

//        log("000")
        lifecycleScope.launch {
            withContext(Dispatchers.IO) {
                getSync()
            }
        }
//        log("555")

        getAsync()
//
//        log("000")
//        lifecycleScope.launch {
//            log("111")
//            withContext(Dispatchers.IO) {
//                log("222")
//                getAsync()
//                log("333")
//            }
//            log("444")
//        }
//        log("555")

//        postAsync()

        postFile()

        downloadFile()

        sendMultipart()
    }

    /**
     * 有时会上传文件同时还需要传其他类型的字段
     */
    private fun sendMultipart() {
        val client = OkHttpClient()
        val file = File(externalCacheDir, "ljy.jpg")
        val requestBody: RequestBody = MultipartBody.Builder()
            .setType(MultipartBody.FORM)
            .addFormDataPart("name", "ljy")
            .addFormDataPart("age", "18")
            .addFormDataPart(
                "image", "header.jpg",
                RequestBody.create(MediaType.parse("image/png"), file)
            )
            .build()
        val request: Request = Request.Builder()
            .header("Authorization", "Client-ID " + "...")
            .url("https://api.imgur.com/3/image")
            .post(requestBody)
            .build()
        client.newCall(request).enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {
                log("onFailure:${e.message}")
            }

            override fun onResponse(call: Call, response: Response) {
                log("onResponse:${response.body()?.string()}")
            }
        })
    }

    private fun downloadFile() {
        val client = OkHttpClient()
        val url = "https://pic3.zhimg.com/v2-dc32dcddfd7e78e56cc4b6f689a24979_xl.jpg"
        val request = Request.Builder()
            .url(url)
            .build()
        client.newCall(request).enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {
                log("onFailure:${e.message}")
            }

            override fun onResponse(call: Call, response: Response) {
                val inputStream = response.body()?.byteStream()
                val fileOutputStream = FileOutputStream(File(externalCacheDir, "ljy.jpg"))
                val buffer = ByteArray(2048)
                var len: Int
                while (inputStream?.read(buffer).also { len = it ?: -1 } != -1) {
                    fileOutputStream.write(buffer, 0, len)
                }
                fileOutputStream.flush()
                log("文件下载成功")
            }
        })
    }

    /**
     * 异步上传文件
     */
    private fun postFile() {
        val client = OkHttpClient()
        //获取要上传的文件
        val file = File(externalCacheDir, "ljy.txt")
        //创建RequestBody：
        val requestBody = RequestBody.create(
            MediaType.parse("text/x-markdown; charset=utf-8"),
            file
        )
        val request = Request.Builder()
            .url("https://api.github.com/markdown/raw")
            .post(requestBody)
            .build()
        client.newCall(request).enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {
                log("onFailure:${e.message}")
            }

            override fun onResponse(call: Call, response: Response) {
                log("onResponse:${response.body()?.string()}")
            }
        })
    }

    private fun postAsync() {

        val client = OkHttpClient()
        val formBody = FormBody.Builder()
            .add("k", "wanAndroid")
            .build()
        val request = Request.Builder()
            .url("https://www.wanandroid.com/article/query/0/json")
            .post(formBody)
            .build()
        val call = client.newCall(request)
        call.enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {
                log("onFailure:${e.message}")
                runOnUiThread { tv.text = e.message }
            }

            override fun onResponse(call: Call, response: Response) {
                val result = response.body()?.string()
                log("onResponse:${result}")
//                tv.text = "onResponse"
                runOnUiThread { tv.text = "onResponse${result}" }
            }

        })
    }

    /**
     * OkHttp异步get请求
     * 注意：回调方法onResponse，onFailure是在 子线程/工作线程 中执行的
     */
    private fun getAsync() {
        log("aaa")
        val client = OkHttpClient()
        val request = Request.Builder()
            .url("https://www.baidu.com")
            .get()
            .build()
        val call = client.newCall(request)
        //前三步是一样的，第四步调用异步方法enqueue
        call.enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {
                log("onFailure:${e.message}")
                runOnUiThread { tv.text = e.message }
            }

            override fun onResponse(call: Call, response: Response) {
                log("onResponse:${response.body()?.string()}")
//                tv.text = "onResponse"
                runOnUiThread { tv.text = "onResponse" }

            }

        })
        log("bbb")
    }

    /**
     * OkHttp同步get请求
     * 注意：发送请求后，就会进入阻塞状态，直到收到响应
     */
    private fun getSync() {
        log("aaa")
        //1. 创建OkHttpClient对象
        //直接创建
        val client1 = OkHttpClient()
        //  public OkHttpClient() {
        //    this(new Builder());
        //  }
        //builder提供了默认值
        val maxCacheSize = (100 * 1024 * 1024).toLong()
        val cache = Cache(
            File(cacheDir, "httpCache2"),
            100 * 1024 * 1024L
        )

        /**
         * 有网时候的缓存
         */
        val netCacheInterceptor = Interceptor { chain ->
            val request = chain.request()
            val response = chain.proceed(request)
            val onlineCacheTime = 30 //在线的时候的缓存过期时间，如果想要不缓存，直接时间设置为0
            response.newBuilder()
                .header("Cache-Control", "public, max-age=$onlineCacheTime")
                .removeHeader("Pragma")
                .build()
        }

        /**
         * 没有网时候的缓存
         */
        val offlineCacheInterceptor = Interceptor { chain ->
            var request = chain.request()
            if (!NetUtil.isNetworkAvailable(this)) {
                val offlineCacheTime = 60 //离线的时候的缓存的过期时间
                request =
                    request.newBuilder()
//                        .cacheControl(
//                            CacheControl
//                                .Builder()
//                                .maxStale(60, TimeUnit.SECONDS)
//                                .onlyIfCached()
//                                .build()
//                        )
                        //两种方式结果是一样的，写法不同
                        .header(
                            "Cache-Control",
                            "public, only-if-cached, max-stale=$offlineCacheTime"
                        )
                        .build()
            }
            chain.proceed(request)
        }

        val cacheInterceptor = Interceptor { chain ->

            val request: Request = chain.request()
            val response: Response = chain.proceed(request)
            response.newBuilder()
                .removeHeader("Pragma")
                .removeHeader("Cache-Control") //cache for 30 days
                .header("Cache-Control", "max-age=" + 3600 * 24 * 30)
                .build()

        }

        /**
         * 一、无论有无网路都添加缓存。
         * 目前的情况是我们这个要addNetworkInterceptor
         * 这样才有效。经过本人测试（chan）测试有效.
         * 60S后如果没有网络将获取不到数据，显示连接失败
         */
        val netInterceptor = Interceptor { chain ->
            val request = chain.request()
            val response = chain.proceed(request)
            /*String cacheControl = request.header("Cache-Control");
             if (TextUtils.isEmpty(cacheControl)) {
                 cacheControl = "public, max-age=60";
             }*/
            val maxAge = 60
            response.newBuilder()
                .removeHeader("Pragma") // 清除头信息，因为服务器如果不支持，会返回一些干扰信息，不清除下面无法生效
                .removeHeader("Cache-Control")
                .header("Cache-Control", "public, max-age=$maxAge")
                .build()
        }

        class CacheInterceptor : Interceptor {
            override fun intercept(chain: Interceptor.Chain): Response {
                var request: Request = chain.request()
                val var10000: Response
                val response: Response
                if (NetUtil.isNetworkAvailable(this@OkHttpDemoActivity)) {
                    //如果有网，返回一个30内有效的响应，则30秒内同一请求会直接从缓存中读取
                    response = chain.proceed(request)
                    //构建maxAge = 30秒的CacheControl
                    val cacheControl = CacheControl.Builder()
                        .maxAge(30, TimeUnit.SECONDS)
                        .build()
                        .toString()
                    var10000 = response.newBuilder()
                        .removeHeader("Pragma")
                        .removeHeader("Cache-Control") //填入30秒的CacheControl
                        .header("Cache-Control", cacheControl)
                        .build()
                } else {
                    //如果没网，用原来的请求重新构建一个强制从缓存中读取的请求
                    request = request.newBuilder()
                        .cacheControl(CacheControl.FORCE_CACHE)
                        .build()
                    var10000 = chain.proceed(request)
                }
                return var10000
            }
        }

        val client = OkHttpClient.Builder()
            .connectTimeout(30, TimeUnit.SECONDS)
            .readTimeout(60, TimeUnit.SECONDS)
            .writeTimeout(90, TimeUnit.SECONDS)
//            .addNetworkInterceptor(netInterceptor)
            .retryOnConnectionFailure(true)
            .addNetworkInterceptor(CacheInterceptor())
//            .addNetworkInterceptor(netCacheInterceptor)
//            .addInterceptor(CacheInterceptor())
            .cache(
                Cache(
                    File(cacheDir, "httpCache2"),
                    100 * 1024 * 1024L
                )
            ).build()
        //2. 创建Request对象
        val request = Request.Builder()
            .url("https://www.baidu.com")
            //有的请求每次都需要最新的数据,则在Request中设置CacheControl.FORCE_NETWORK
//            .cacheControl(CacheControl.FORCE_CACHE)
//            .cacheControl(CacheControl.Builder().maxStale(10,TimeUnit.SECONDS).build())
            .get()
            .build()
        //3. 将request封装成call对象
        val call = client.newCall(request)
//        //4. 调用call的execute发送同步请求
        val response = call.execute()
        if (response.isSuccessful) {
            if (null != response.cacheResponse()) {
                log("cache:" + response.cacheResponse())
            } else {
                log("net:" + response.networkResponse())
            }
            log(response.body()?.string())
        } else {
            log(IOException("Unexpected code $response").message)
        }
//        val response = client.newCall(request).execute()
//        response.body()?.close()
//        log("network response = " + response.networkResponse())
//        log("cache response = " + response.cacheResponse())
//        log("bbb")
//        val response2 = client.newCall(request).execute()
//        response2.body()?.close()
//        log("network response2 = " + response2.networkResponse())
//        log("cache response2 = " + response2.cacheResponse())
//        log("bbb")
    }
}


@SuppressLint("SimpleDateFormat")
val dateFormat = SimpleDateFormat("HH:mm:ss:SSS")
val now = {
    dateFormat.format(Date(System.currentTimeMillis()))
}

fun log(msg: Any?) = LjyLogUtil.d("${now()} [${Thread.currentThread().name}] $msg")